/**
 * @author:albert
 */

package com.bkbw.live.common.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.badlogic.gdx.math.MathUtils;

public class Utils {
	static Logger logger = LoggerFactory.getLogger("mylog");
	public static String getSuperFields(Object object) {
		String ret = "";
		ret += getFields(object.getClass(), object);
		Class superClass = object.getClass().getSuperclass();
		while (!superClass.equals(Object.class)) {
			ret += getFields(superClass, object);
			superClass = superClass.getSuperclass();
		}
		return ret;
	}
	
	public static String getFields(Object object) {
		String ret = "";
		Class cls = object.getClass();
		return getFields(cls, object);
	}
	
	public static String getFields(Class dstCls, Object object) {
		String ret = "";
		Class cls = dstCls;
		Field[] fields = cls.getDeclaredFields();
		
		for (Field field : fields){
			field.setAccessible(true);
			String name = field.getName();
			ret += name + " ";
			try {
				Object value = field.get(object);
				ret += value + " ";
			}
			catch (Exception e){
				ret += "null ";
			}
		}
		return ret;
	}
	
	private static String decorateFieldName(String tmps){
		StringBuilder builder = new StringBuilder();
		builder.append(tmps.substring(0, 1).toUpperCase());
		builder.append(tmps.substring(1));
		//tmps = tmps.substring(0, 1).toUpperCase() + tmps.substring(1);
		// for proto buf messages only
		if (tmps.endsWith("_")) {
			builder.deleteCharAt(tmps.length() - 1);
		}
		return builder.toString();
	}
	
	private static String FirstToUpper(String tmps){
		tmps = tmps.substring(0, 1).toUpperCase() + tmps.substring(1);
		return tmps;
	}
	
	// 把src的字段拷贝给dst，以dst的字段为主，dst的父类字段也会被处理
	public static void copySuperFieldsFromBean(Object dst, Object src) {
		copyFieldsFromBean(dst.getClass(), dst, src);
		Class superClass = dst.getClass().getSuperclass();
		while (!superClass.equals(Object.class)) {
			copyFieldsFromBean(superClass, dst, src);
			superClass = superClass.getSuperclass();
		}
	}
	
	public static void copyFieldsFromBean(Object dst, Object src) {
		Class dstCls = dst.getClass();
		copyFieldsFromBean(dstCls, dst, src);
	}
	
	public static void copyFieldsFromBean(Class dstCls, Object dst, Object src) {
		//Class dstCls = dst.getClass();
		Class srcCls = src.getClass();
		Field[] dstFields = dstCls.getDeclaredFields();
		for (Field field : dstFields) {
			Method dstGetter = null;
			try {
				dstGetter = dstCls.getMethod("get" + decorateFieldName(field.getName()));
			}
			catch (NoSuchMethodException e){
				//logger.debug("NoSuchMethodException dstGetter " + field.toString());
				continue;
			}
			Method srcGetter = null;
			try {
				srcGetter = srcCls.getMethod("get" + decorateFieldName(field.getName()));
			}
			catch (NoSuchMethodException e){
				//logger.debug("NoSuchMethodException srcGetter " + field.toString());
				continue;
			}
			// for protobuf
			// 如果src是protobuf的消息类，那么需要调用hasXx来检测字段是否存在。
			// 因为protobuf的字段使用has来判断是否存在，has为true表示存在，可以提取字段，has为false表示不存在，但该字段仍然可以访问其默认值
			if (src instanceof com.google.protobuf.GeneratedMessage) {
				Method srcHas = null;
				try {
					srcHas = srcCls.getMethod("has" + decorateFieldName(field.getName()));
					Object has = srcHas.invoke(src);
					if (has instanceof Boolean) {
						if (!(Boolean)has){
							continue;
						}
					}
				
				}
				catch (Exception e){
					//e.printStackTrace();
				}
			}
			
			try {
				Method setter = dstCls.getMethod("set" + decorateFieldName(field.getName()), dstGetter.getReturnType());
				Object value = srcGetter.invoke(src);
				if (value == null) {
					continue;
				}
				setter.invoke(dst, value);
			}
			catch (Exception e){
				System.out.println("problem field is "+field+" dst type "+dstGetter.getReturnType().getName() + " src type " + srcGetter.getReturnType().getName());
				e.printStackTrace();
			}
			
		}
	}
	
	// 把src的字段拷贝给dst，以src的字段为主，src的父类字段也会被处理
	public static void copySuperFieldsToBean(Object src, Object dst) {
		copyFieldsToBean(src, dst);
		Class superClass = src.getClass().getSuperclass();
		while (!superClass.equals(Object.class)) {
			copyFieldsToBean(superClass, src, dst);
			superClass = superClass.getSuperclass();
		}
	}
	
	public static void copyFieldsToBean(Object src, Object dst) {
		Class srcCls = src.getClass();
		copyFieldsToBean(srcCls, src, dst);
	}
	
	public static void copyFieldsToBean(Class srcCls, Object src, Object dst) {
		Class dstCls = dst.getClass();
		//Class srcCls = src.getClass();
		Field[] srcFields = srcCls.getDeclaredFields();
		for (Field field : srcFields) {
			Method dstGetter = null;
			try {
				dstGetter = dstCls.getMethod("get" + decorateFieldName(field.getName()));
			}
			catch (NoSuchMethodException e){
				//logger.debug("NoSuchMethodException dstGetter " + field.toString());
				continue;
			}
			Method srcGetter = null;
			try {
				srcGetter = srcCls.getMethod("get" + decorateFieldName(field.getName()));
			}
			catch (NoSuchMethodException e){
				//logger.debug("NoSuchMethodException srcGetter " + field.toString());
				continue;
			}
			// for protobuf
			// 如果src是protobuf的消息类，那么需要调用hasXx来检测字段是否存在。
			// 因为protobuf的字段使用has来判断是否存在，has为true表示存在，可以提取字段，has为false表示不存在，但该字段仍然可以访问其默认值
			if (src instanceof com.google.protobuf.GeneratedMessage) {
				Method srcHas = null;
				try {
					srcHas = srcCls.getMethod("has" + decorateFieldName(field.getName()));
					Object has = srcHas.invoke(src);
					if (has instanceof Boolean) {
						if (!(Boolean)has){
							continue;
						}
					}
				
				}
				catch (Exception e){
					//e.printStackTrace();
				}
			}
			
			try {
				Method setter = dstCls.getMethod("set" + decorateFieldName(field.getName()), dstGetter.getReturnType());
				Object value = srcGetter.invoke(src);
				if (value == null) {
					continue;
				}
				setter.invoke(dst, value);
			}
			catch (Exception e){
				System.out.println("problem field is "+field+" dst type "+dstGetter.getReturnType().getName() + " src type " + srcGetter.getReturnType().getName());
				e.printStackTrace();
			}
			
		}
	}
	
	public enum FieldOperation {
		FO_ADD,
		FO_SUB
	}
	
	// 把dst的字段加或减src中对应字段的值，以src的字段为主，src的父类字段也会被处理
	public static void operationSuperFieldsToBean(Object src, Object dst, FieldOperation op) {
		operationFieldsToBean(src, dst, op);
		Class superClass = src.getClass().getSuperclass();
		while (!superClass.equals(Object.class)) {
			operationFieldsToBean(superClass, src, dst, op);
			superClass = superClass.getSuperclass();
		}
	}
	
	public static void operationFieldsToBean(Object src, Object dst, FieldOperation op) {
		Class srcCls = src.getClass();
		operationFieldsToBean(srcCls, src, dst, op);
	}
	
	public static void operationFieldsToBean(Class srcCls, Object src, Object dst, FieldOperation op) {
		Class dstCls = dst.getClass();
		//Class srcCls = src.getClass();
		Field[] srcFields = srcCls.getDeclaredFields();
		for (Field field : srcFields) {
			Method dstGetter = null;
			try {
				dstGetter = dstCls.getMethod("get" + decorateFieldName(field.getName()));
			}
			catch (NoSuchMethodException e){
				//logger.debug("NoSuchMethodException dstGetter " + field.toString());
				continue;
			}
			Method srcGetter = null;
			try {
				srcGetter = srcCls.getMethod("get" + decorateFieldName(field.getName()));
			}
			catch (NoSuchMethodException e){
				//logger.debug("NoSuchMethodException srcGetter " + field.toString());
				continue;
			}
			// for protobuf
			// 如果src是protobuf的消息类，那么需要调用hasXx来检测字段是否存在。
			// 因为protobuf的字段使用has来判断是否存在，has为true表示存在，可以提取字段，has为false表示不存在，但该字段仍然可以访问其默认值
			if (src instanceof com.google.protobuf.GeneratedMessage) {
				Method srcHas = null;
				try {
					srcHas = srcCls.getMethod("has" + decorateFieldName(field.getName()));
					Object has = srcHas.invoke(src);
					if (has instanceof Boolean) {
						if (!(Boolean)has){
							continue;
						}
					}
				
				}
				catch (Exception e){
					//e.printStackTrace();
				}
			}
			
			
			try {
				Method setter = dstCls.getMethod("set" + decorateFieldName(field.getName()), dstGetter.getReturnType());
				Object value = srcGetter.invoke(src);
				Object dstValue = dstGetter.invoke(dst);
				if (value == null || dstValue == null) {
					continue;
				}
				
				if (value instanceof Integer && dstValue instanceof Integer) {
					Integer ivalue = (Integer)value;
					Integer iDstValue = (Integer)dstValue;
					if (op == FieldOperation.FO_ADD) {
						setter.invoke(dst, ivalue + iDstValue);
					}
					else if (op == FieldOperation.FO_SUB) {
						setter.invoke(dst, iDstValue - ivalue);
					}
				}
				if (value instanceof Long && dstValue instanceof Long) {
					Long ivalue = (Long)value;
					Long iDstValue = (Long)dstValue;
					if (op == FieldOperation.FO_ADD) {
						setter.invoke(dst, ivalue + iDstValue);
					}
					else if (op == FieldOperation.FO_SUB) {
						setter.invoke(dst, iDstValue - ivalue);
					}
				}
				if (value instanceof Float && dstValue instanceof Float) {
					Float ivalue = (Float)value;
					Float iDstValue = (Float)dstValue;
					if (op == FieldOperation.FO_ADD) {
						setter.invoke(dst, ivalue + iDstValue);
					}
					else if (op == FieldOperation.FO_SUB) {
						setter.invoke(dst, iDstValue - ivalue);
					}
				}
				if (value instanceof Double && dstValue instanceof Double) {
					Double ivalue = (Double)value;
					Double iDstValue = (Double)dstValue;
					if (op == FieldOperation.FO_ADD) {
						setter.invoke(dst, ivalue + iDstValue);
					}
					else if (op == FieldOperation.FO_SUB) {
						setter.invoke(dst, iDstValue - ivalue);
					}
				}
			}
			catch (Exception e){
				System.out.println("problem field is "+field+" dst type "+dstGetter.getReturnType().getName() + " src type " + srcGetter.getReturnType().getName());
				e.printStackTrace();
			}
			
		}
	}
	
	// 把dst的字段加或减src中对应字段的值，以dst的字段为主，dst的父类字段也会被处理
	public static void operationSuperFieldsFromBean(Object dst, Object src, FieldOperation op) {
		operationFieldsFromBean(dst.getClass(), dst, src, op);
		Class superClass = dst.getClass().getSuperclass();
		while (!superClass.equals(Object.class)) {
			operationFieldsFromBean(superClass, dst, src, op);
			superClass = superClass.getSuperclass();
		}
	}
	
	public static void operationFieldsFromBean(Object dst, Object src, FieldOperation op) {
		Class dstCls = dst.getClass();
		operationFieldsFromBean(dstCls, dst, src, op);
	}
	
	public static void operationFieldsFromBean(Class dstCls, Object dst, Object src, FieldOperation op) {
		//Class dstCls = dst.getClass();
		Class srcCls = src.getClass();
		Field[] dstFields = dstCls.getDeclaredFields();
		for (Field field : dstFields) {
			Method dstGetter = null;
			try {
				dstGetter = dstCls.getMethod("get" + decorateFieldName(field.getName()));
			}
			catch (NoSuchMethodException e){
				//logger.debug("NoSuchMethodException dstGetter " + field.toString());
				continue;
			}
			Method srcGetter = null;
			try {
				srcGetter = srcCls.getMethod("get" + decorateFieldName(field.getName()));
			}
			catch (NoSuchMethodException e){
				//logger.debug("NoSuchMethodException srcGetter " + field.toString());
				continue;
			}
			// for protobuf
			// 如果src是protobuf的消息类，那么需要调用hasXx来检测字段是否存在。
			// 因为protobuf的字段使用has来判断是否存在，has为true表示存在，可以提取字段，has为false表示不存在，但该字段仍然可以访问其默认值
			if (src instanceof com.google.protobuf.GeneratedMessage) {
				Method srcHas = null;
				try {
					srcHas = srcCls.getMethod("has" + decorateFieldName(field.getName()));
					Object has = srcHas.invoke(src);
					if (has instanceof Boolean) {
						if (!(Boolean)has){
							continue;
						}
					}
				
				}
				catch (Exception e){
					//e.printStackTrace();
				}
			}
			
			try {
				Method setter = dstCls.getMethod("set" + decorateFieldName(field.getName()), dstGetter.getReturnType());
				Object value = srcGetter.invoke(src);
				Object dstValue = dstGetter.invoke(dst);
				if (value == null || dstValue == null) {
					continue;
				}
				
				if (value instanceof Integer && dstValue instanceof Integer) {
					Integer ivalue = (Integer)value;
					Integer iDstValue = (Integer)dstValue;
					if (op == FieldOperation.FO_ADD) {
						setter.invoke(dst, ivalue + iDstValue);
					}
					else if (op == FieldOperation.FO_SUB) {
						setter.invoke(dst, iDstValue - ivalue);
					}
				}
				if (value instanceof Long && dstValue instanceof Long) {
					Long ivalue = (Long)value;
					Long iDstValue = (Long)dstValue;
					if (op == FieldOperation.FO_ADD) {
						setter.invoke(dst, ivalue + iDstValue);
					}
					else if (op == FieldOperation.FO_SUB) {
						setter.invoke(dst, iDstValue - ivalue);
					}
				}
				if (value instanceof Float && dstValue instanceof Float) {
					Float ivalue = (Float)value;
					Float iDstValue = (Float)dstValue;
					if (op == FieldOperation.FO_ADD) {
						setter.invoke(dst, ivalue + iDstValue);
					}
					else if (op == FieldOperation.FO_SUB) {
						setter.invoke(dst, iDstValue - ivalue);
					}
				}
				if (value instanceof Double && dstValue instanceof Double) {
					Double ivalue = (Double)value;
					Double iDstValue = (Double)dstValue;
					if (op == FieldOperation.FO_ADD) {
						setter.invoke(dst, ivalue + iDstValue);
					}
					else if (op == FieldOperation.FO_SUB) {
						setter.invoke(dst, iDstValue - ivalue);
					}
				}
			}
			catch (Exception e){
				System.out.println("problem field is "+field+" dst type "+dstGetter.getReturnType().getName() + " src type " + srcGetter.getReturnType().getName());
				e.printStackTrace();
			}
			
		}
	}
	
	public static void dumpObject(Object object){
		System.out.println(getFields(object));
	}
	
	public static void dumpSuperObject(Object object){
		System.out.println(getSuperFields(object));
	}
	
	public static void dumpList(List<?> list) {
		for (Object object : list) {
			dumpObject(object);
		}
	}
	
	public static float uniformFloat(float low, float high) {
		return MathUtils.random(low, high);
	}
	
	public static int uniformInt(int low, int high) {
		return MathUtils.random(low, high);
	}
	
	public static String exceptionStack(Exception e){
		StringBuilder builder = new StringBuilder();
		//String stackString = "";
		builder.append(e.getMessage());
		StackTraceElement[] elements = e.getStackTrace();
		if (elements != null) {
    		for (StackTraceElement ee : elements) {  
    			builder.append(ee.toString() + "\r\n");
            }
		}
		return builder.toString();
	}

	
}
